package ysjsonrpc

import (
	"context"
	"gitee.com/kmyss/gf-ex/yslog"
	"github.com/gogf/gf/v2/container/gmap"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/glog"
)

const (
	defaultName = "default"
	configName  = "ys.jsonrpc"
)

var (
	localInstance = gmap.NewStrAnyMap(true)
)

type Manager interface {
	
	// Register 注册处理函数
	Register(context.Context, string, FuncHandler) error
	
	// Call 根据 RPC 执行函数
	Call(context.Context, *JsonRPCReq) *JsonRPCRes
	
	// CallByString 字符串形式的 RPC 执行函数
	CallByString(context.Context, string) *JsonRPCRes
	
	// CallByBytes Byte 数组形式的 RPC 执行函数调用
	CallByBytes(context.Context, []byte) *JsonRPCRes
	
	// Run 线程形式运行的 RPC 函数, 结果会在 ResultCh 中
	Run(context.Context, *JsonRPCReq)
	
	// RunByString 字符串形式的运行
	RunByString(context.Context, string)
	
	// RunByBytes Byte 数组形式的运行
	RunByBytes(context.Context, []byte)
	
	// ResultCh 结果通道
	ResultCh() <-chan *JsonRPCRes
}

func Instance(name ...string) Manager {
	instanceName := defaultName
	if len(name) > 0 && name[0] != "" {
		instanceName = name[0]
	}
	
	return localInstance.GetOrSetFunc(instanceName, func() interface{} {
		manger := newManager()
		return manger
	}).(Manager)
}

func newManager() Manager {
	s := &simpleManager{
		methods:  gmap.NewStrAnyMap(true),
		resultCh: make(chan *JsonRPCRes, 100),
	}
	return s
}

type simpleManager struct {
	l *glog.Logger
	
	methods  *gmap.StrAnyMap
	resultCh chan *JsonRPCRes
}

func (s *simpleManager) log() *glog.Logger {
	if s.l == nil {
		s.l = yslog.Log(configName)
	}
	return s.l
}

func (m *simpleManager) Register(ctx context.Context, method string, handler FuncHandler) error {
	if !m.methods.SetIfNotExist(method, handler) {
		err := gerror.Newf("%s 方法已存在!", method)
		m.log().Error(ctx, err)
		return err
	}
	m.log().Info(ctx, "注册函数:", method)
	return nil
}

func (m *simpleManager) Call(ctx context.Context, req *JsonRPCReq) *JsonRPCRes {
	if ctx != nil {
		req.Ctx = ctx
	}
	
	m.log().Debug(req.Ctx, req)
	
	if !m.hasMethod(req.Method) {
		m.log().Error(req.Ctx, "调用不存在的方法", req.Method)
		return NewJsonRPCResWithError(req, methodNotFound)
	}
	
	m.log().Info(req.Ctx, "执行函数:", req.Method)
	result, err := m.methods.Get(req.Method).(FuncHandler)(req.Params)
	if err != nil {
		m.log().Error(req.Ctx, "方法执行失败", err)
		return NewJsonRPCResWithError(req, err)
	}
	return NewJsonRPCResWithResult(req, result)
}

func (m *simpleManager) CallByString(ctx context.Context, s string) *JsonRPCRes {
	req := NewJsonrpcReq(s)
	if ctx != nil {
		req.Ctx = ctx
	} else {
		req.Ctx = gctx.New()
	}
	
	if req == nil {
		m.log().Error(req.Ctx, "json字符解析失败", req)
		m.log().Debug(req.Ctx, "原始数据:", s)
		return NewJsonRPCResWithError(DefaultReq(), parseError)
	}
	return m.Call(nil, req)
}

func (m *simpleManager) CallByBytes(ctx context.Context, bytes []byte) *JsonRPCRes {
	return m.CallByString(ctx, string(bytes))
}

func (m *simpleManager) Run(ctx context.Context, req *JsonRPCReq) {
	go func() {
		m.resultCh <- m.Call(ctx, req)
	}()
}

func (m *simpleManager) RunByString(ctx context.Context, s string) {
	go func() {
		m.resultCh <- m.CallByString(ctx, s)
	}()
}

func (m *simpleManager) RunByBytes(ctx context.Context, bytes []byte) {
	go func() {
		m.resultCh <- m.CallByBytes(ctx, bytes)
	}()
}

func (m *simpleManager) ResultCh() <-chan *JsonRPCRes {
	return m.resultCh
}

func (m *simpleManager) hasMethod(method string) bool {
	return m.methods.Contains(method)
}
